﻿using Portal.FileSystemData;
using Portal.Modules.ImageBrowser;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Xml.Xsl;
using System.Xml;
using System.Text;

/// <summary>
/// A class that performs data update to the current data structure.
/// </summary>
public class ImageBrowserUpdater
{
  private const string OldDirConfigFile = "_dirconfig.xml";
  private const string OldFileConfigFile = "_fileconfig.xml";
  private XslCompiledTransform _transformFile = null;

	public ImageBrowserUpdater()
	{
	}

  /// <summary>
  /// Updates an old data structure if necessary.
  /// </summary>
  /// <param name="config">The configuration object of the module.</param>
  internal void Update(ImageBrowserConfig config)
  {
    // Does the new configuration file already exist?
    string currentPath = Path.Combine(config.PicturePhysicalPath, DirectoryWrapper.CustomDataFile);
    if (!File.Exists(currentPath))
    {
      // Does an old file exist?
      if (File.Exists(Path.Combine(config.PicturePhysicalPath, OldDirConfigFile))
        || File.Exists(Path.Combine(config.PicturePhysicalPath, OldFileConfigFile)))
      {
        DirectoryInfo dirInfo = new DirectoryInfo(config.PicturePhysicalPath);
        BuildNewConfig(dirInfo);
      }
    }
    
  }

  /// <summary>
  /// Builds the new configuration files for the directories.
  /// </summary>
  private void BuildNewConfig(DirectoryInfo dirInfo)
  {
    // Update this directory.
    string outputPath = Path.Combine(dirInfo.FullName, DirectoryWrapper.CustomDataFile);
    if(!File.Exists(outputPath))
    {
      // Merge the two old configuration files, if they exist.
      string dirConfigFile = Path.Combine(dirInfo.FullName, OldDirConfigFile);
      bool dirConfigFileExist = File.Exists(dirConfigFile);
      string fileConfigFile = Path.Combine(dirInfo.FullName, OldFileConfigFile);
      bool fileConfigFileExist = File.Exists(fileConfigFile);
      if(dirConfigFileExist || fileConfigFileExist)
      {
        // Create the new configuration File.
        XmlTextWriter outputWriter = new XmlTextWriter(outputPath, Encoding.UTF8);
        outputWriter.Formatting = Formatting.Indented;
        outputWriter.WriteStartDocument();

        XmlDocument outputDoc = new XmlDocument();

        outputWriter.WriteStartElement("DirectoryData");
        outputWriter.WriteAttributeString("xmlns", "http://tempuri.org/DirectoryData.xsd");

        // Transfer the directory Info.
        if (dirConfigFileExist)
        {
          // Create the output directory Node.
          outputWriter.WriteStartElement("DirectoryConfig");
          
          XmlDocument inputDoc = new XmlDocument();
          inputDoc.Load(dirConfigFile);
          XmlNamespaceManager nsmgr = new XmlNamespaceManager(inputDoc.NameTable);
          nsmgr.AddNamespace("ds", "http://tempuri.org/DirectorySettingsData.xsd");

          XmlNode settingsNode = inputDoc.DocumentElement.SelectSingleNode("ds:DirectorySettings", nsmgr);
          if (settingsNode != null)
          {
            TransferValue(settingsNode, "ds:Caption", nsmgr, outputWriter, "PresentationName");
            TransferValue(settingsNode, "ds:Tooltip", nsmgr, outputWriter, "Tooltip");
            TransferValue(settingsNode, "ds:Description", nsmgr, outputWriter, "Description");
            TransferValue(settingsNode, "ds:ContentOrderAscending", nsmgr, outputWriter, "ContentOrderAscending");
          }
          outputWriter.WriteEndElement();
        }

        // Transfer the file Info.
        if (fileConfigFileExist)
        {
          // Itereate over alle the file infors in the source document.
          XmlDocument inputDoc = new XmlDocument();
          inputDoc.Load(fileConfigFile);
          XmlNamespaceManager nsmgr = new XmlNamespaceManager(inputDoc.NameTable);
          nsmgr.AddNamespace("fs", "http://tempuri.org/FilelistSettingsData.xsd");
          var allfileInfos = inputDoc.DocumentElement.SelectNodes("fs:FilelistSettings", nsmgr);
          foreach (XmlNode srcfileInfo in allfileInfos)
          {
            outputWriter.WriteStartElement("FileConfig");

            TransferValue(srcfileInfo, "fs:FileName", nsmgr, outputWriter, "Name");
            TransferValue(srcfileInfo, "fs:Caption", nsmgr, outputWriter, "PresentationName");
            TransferValue(srcfileInfo, "fs:Tooltip", nsmgr, outputWriter, "Tooltip");
            TransferValue(srcfileInfo, "fs:Description", nsmgr, outputWriter, "Description");
            outputWriter.WriteEndElement();
          }
        }

        outputWriter.WriteEndElement();
        outputWriter.Close();
        
        // Delete the old files.
        if (dirConfigFileExist)
          File.Delete(dirConfigFile);
        if (fileConfigFileExist)
          File.Delete(fileConfigFile);

        // Delete Old Cache Path.
        string path = Path.Combine(dirInfo.FullName, "thumbs");
        if (Directory.Exists(path))
          Directory.Delete(path, true);
        path = Path.Combine(dirInfo.FullName, "webpics");
        if (Directory.Exists(path))
          Directory.Delete(path, true);
      }
    }

    // Update all subdirectories.
    DirectoryInfo[] subDir = dirInfo.GetDirectories();
    foreach (DirectoryInfo subDirInfo in subDir)
    {
      if (subDirInfo.Name[0] != '_')
      {
        BuildNewConfig(subDirInfo);
      }
    }    
  }
  /// <summary>
  /// Transfers the value of an xml node if this node exist in the source.
  /// </summary>
  /// <param name="sourceParent"></param>
  /// <param name="sourceNodeName"></param>
  /// <param name="sourceNsMgr"></param>
  /// <param name="destinationParent"></param>
  /// <param name="destinationNodeName"></param>
  private XmlNode TransferValue(XmlNode sourceParent, String sourceNodeName, XmlNamespaceManager sourceNsMgr, XmlTextWriter outputWriter, String destinationNodeName)
  {
    XmlNode newNode = null;
    XmlNode sourceNode = sourceParent.SelectSingleNode(sourceNodeName, sourceNsMgr);
    if (sourceNode != null)
    {
      outputWriter.WriteElementString(destinationNodeName, sourceNode.InnerText);
    }
    return newNode;
  }

  private XslCompiledTransform TransformFile
  {
    get
    {
      if (_transformFile == null)
      {
        _transformFile = new XslCompiledTransform();
        _transformFile.Load("UpgradeImageBrowserData.xsl");
      }
      return _transformFile;
    }
  }
}